import React, { Component } from 'react'
import PubSub from 'pubsub-js'
import Header from './components/Header/Header'
import List from './components/List/List'
import Footer from './components/Footer/Footer'
//引入context对象
import context from './context'

import './App.css'

// 结构context上面的Provider组件
const { Provider } = context

export default class App extends Component {
  // 把多个组件都要用到的数据,定义在他们共同的父组件中.这个行为叫做状态提升
  state = {
    todos: JSON.parse(localStorage.getItem('todos')) || [],

    // 这个数据,用来判断哪个Item组件需要展示文本框. 由于这个标记要用于排他,所以需要明确当前要展示文本框的Item是谁,应该用id作为标记
    id: undefined,
  }

  componentDidMount() {
    // 订阅,接收任务名,用于添加任务
    this.addId = PubSub.subscribe('add', (topic, todoName) => {
      // 根据任务名,创建任务对象
      const todo = {
        id: Date.now(),
        todoName,
        isDone: false,
      }
      // 往数组中添加新任务
      // this.state.todos.push(todo) 不建议这样写
      // 推荐写法: 根据旧数据,创建新数据
      const newTodos = [...this.state.todos]
      newTodos.push(todo)

      // 1. 修改todos的数据 2. 导致App中render函数重新执行
      // 注意: 父组件更新,默认会导致所有的子组件也更新
      this.setState({
        todos: newTodos,
      })
    })
    // 订阅,删除一条任务
    this.delId = PubSub.subscribe('del', (topic, id) => {
      // 根据id,将todos里面的某个对象删除
      const newTodos = this.state.todos.filter((item) => item.id !== id)
      this.setState({
        todos: newTodos,
      })
    })
  }

  // 组件卸载的时候,要清除订阅
  componentWillUnmount() {
    PubSub.unsubscribe(this.addId)
    PubSub.unsubscribe(this.delId)
  }

  // 修改一条任务的状态
  updateTodo = (id, isDone) => {
    const newTodos = this.state.todos.map((item) => {
      if (item.id === id) item.isDone = isDone
      return item
    })
    this.setState({
      todos: newTodos,
    })
  }

  // 全选按钮
  allCheckHandle = () => {
    // 先遍历我们的数据,查看是否所有的数据都选中了
    const isAllDone = this.state.todos.every((item) => item.isDone)
    // 如果isAllDone是true,那么所有的数据应该改成false. 否则,所有数据改成true
    const newTodos = this.state.todos.map((item) => {
      item.isDone = !isAllDone
      return item
    })

    this.setState({
      todos: newTodos,
    })
  }

  // 清除所有完成任务
  clearAllDone = () => {
    const newTodos = this.state.todos.filter((item) => !item.isDone)
    this.setState({
      todos: newTodos,
    })
  }

  // 用来修改id.从而排他的展示点击数据的文本框
  editToggle = (id) => {
    // 如果点击时,按钮的文字是编辑,则设置id.否则将id设置为undefined
    this.setState({
      // 如果当前状态的id和传过来的id是同一个,则认为是取消.否则任务是编辑
      id: this.state.id === id ? undefined : id,
    })
  }

  // 修改任务名
  editTodo = (id, todoName) => {
    const newTodos = this.state.todos.map((item) => {
      if (item.id === id) item.todoName = todoName
      return item
    })
    this.setState({
      todos: newTodos,
      id: undefined,
    })
  }

  render() {
    const { todos, id } = this.state
    // 每次修改数据,就一定会执行setState.就会导致render函数重新执行.所以这里解构的todos就是每一次修改修改之后的最新数据.本地缓存写在这里就可以
    localStorage.setItem('todos', JSON.stringify(todos))

    return (
      <Provider value={id}>
        <div className="todo-container">
          <div className="todo-wrap">
            <Header></Header>
            {todos.length ? (
              <div>
                <List
                  todos={todos}
                  updateTodo={this.updateTodo}
                  editToggle={this.editToggle}
                  editTodo={this.editTodo}
                ></List>
                <Footer
                  todos={todos}
                  allCheckHandle={this.allCheckHandle}
                  clearAllDone={this.clearAllDone}
                ></Footer>
              </div>
            ) : (
              <h1>恭喜你,暂无任务</h1>
            )}
          </div>
        </div>
      </Provider>
    )
  }
}
